# -*- coding: utf-8 -*-
from constants import *

class GameObject(Sprite):
    
    def __init__(self, pos, image_data, acc=[0,0]):
        """
            Base classe para todos os objetos do jogo.
            Todo objeto que possa iteragir com o player de alguma
            forma, deve extender essa classe.

            Inicializa os atributos gerais de todos os objetos.
            
            image: deve ser um objeto do tipo pygame.Image
            
            pos: deve ser um vetor com dois elementos (x, y) representando as coordenadas
                do objeto no jogo. devemos usar um objeto mutável desde que devemos
                mudar as posições do objeto ao longo do jogo.

            acc: deve ser um vetor com dois elementos (x, y) representando as direções
                (aceleração) em que o objeto está se movendo. deve usar um objeto
                mutável desde que devemos mudar a direção em que o objeto se move.
                por padrão a aceleração é [0,0]
            
        """
        Sprite.__init__(self)
        self.image_data = image_data
        self.image = self.image_data.get_image()
        self.rect = self.image.get_rect(center = pos)
        if self.is_animated():
            self.area = Rect((0,0),self.get_size())
        if self.get_lifespan() > 0:
            self.lifetime = 0
        self.pos = list(pos)
        self.acc = list(acc)

    def is_animated(self):
        return self.image_data.is_animated()

    def get_size(self):
        return self.image_data.get_size()

    def get_offset(self):
        return self.image_data.get_offset()

    def get_lifespan(self):
        return self.image_data.get_lifespan()
    
    def get_pos(self):
        """
            Retorna a posição (x,y) atual do objeto.
        """
        return self.pos

    def get_image(self):
        """
            retorna a imagem atual do objeto.
        """
        return self.image

    def get_rect(self):
        """
            Retorna uma instancia de Rect da imagem.
        """
        return self.rect

    def update(self, *args):
        """
            Esse método deve ser sobreescrito pelas sub classes.
        """
        if self.acc != [0,0]:
            self.pos[0] += self.acc[0]
            self.pos[1] += self.acc[1]
            self.rect.center = self.pos

        if self.is_animated():
            self.area.x += self.get_offset()

        if self.get_lifespan() > 0:
            if self.lifetime >= self.get_lifespan():
                self.kill()
            self.lifetime += 1

    def draw(self, screen):
        if self.is_animated():
            screen.blit(self.image, self.pos, self.area)
        else:
            screen.blit(self.image, self.rect)

    def move_to(self, dest):
        dx = dest[0] - self.pos[0]
        dy = self.pos[1] - dest[1]
        angle = math.degrees(math.atan2(dy, dx))
        self.image = transform.rotate(self.image_data.get_image(), angle-90)
        self.rect = self.image.get_rect(center = self.rect.center)
        self.angle_to_vector(math.radians(angle))

    def angle_to_vector(self, angle):
        self.acc =[math.cos(angle)*3, -math.sin(angle)*3]
        
class Shot(GameObject):

    def __init__(self, pos, image_data, acc=[0,0], isGuided=False):
        """
            Classe que representa o tiro dado pelas naves,
            se o tiro for dado pelo player o parametro isFriendly deve ser True
        """
        GameObject.__init__(self, pos, image_data, acc)
        self.isGuided = isGuided

class Item(GameObject):
    
    def __init__(self, pos, image_data, acc=[1,1], itype=0):
        """
            Classe que representa os items (bonus) que o player pode adquirir.
            types:
                0 - Weapons
                1 - Shields
                2 - Life
        """
        Object.__init__(self, pos, image_data, acc)
        self.itype = itype
        

class Playable(GameObject):
    """
        Classe Base para as naves.
    """
    
    def shot(self):
        """
            Este método deve ser sobreescrito.
        """
        return
    
    def on_destruction(self, events):
        # HACK, enquanto não usar as imagens corretas...
        events.add(GameObject(self.rect.inflate(70,70).topleft, EXPLOSION))


class Player(Playable):
    """
        Classe que representa o player, todo o comportamento do player deve ser
        implementado nessa classe.
    """
    def __init__(self, pos, image_data, acc=[0,0]):
        
        Playable.__init__(self, pos, image_data, acc = [0,0])
        self.is_shotting = False
        self.list_shot = Group()
        self.shot_delay = 0

    def shot(self):
        pos = [self.pos[0], self.pos[1] - self.image.get_height() /2]
        self.shots.add(Shot(pos, SHOT_IMAGE, (0,-6)))
        self.shot_delay = 25

    @property
    def shots(self):
        return self.list_shot

    def update(self, *args):
        """
            Método chamado a cada loop do jogo.
            Toda ação do player deve ser implementada aqui.
            
            XXX atualmente apenas movimento está completa.
        """
        self.validate_pos()
        if self.is_shotting and self.shot_delay <= 0:
            self.shot()
        self.shot_delay -= 1

    def validate_pos(self):
        """
         valida a posição do player. Não deixa que o player, saia da tela do jogo.
        """
        if self.acc == [0,0]:
            return

        tmp = self.rect.move(self.acc)
        if self.acc[0] != 0 and 0 <= tmp.left and tmp.right <= WIDTH:
            self.pos[0] += self.acc[0]

        if self.acc[1] != 0 and 0 <= tmp.top and tmp.bottom <= HEIGHT:
            self.pos[1] += self.acc[1]

        self.rect.center = self.pos
    
    def set_yacc(self, acc):
        """
            Modifica a aceleração do player com relação ao eixo y.
        """
        self.acc[1] += acc

    def set_xacc(self, acc):
        """
            Modifica a aceleração do player com relação ao eixo x.
        """
        self.acc[0] += acc
        if self.acc[0] == 0:
            self.change_image(PLAYER_IMAGE)
        elif self.acc[0] < 0:
            self.change_image(PLAYER_IMAGE_L)
        else:
            self.change_image(PLAYER_IMAGE_R)
            

    def set_isShotting(self, val):
        """
            estabelece o estado do player, se ele está atirando ou não.
        """
        self.is_shotting = val

    def change_image(self, image_data):
        self.image = image_data.get_image()
        self.rect = self.image.get_rect(center = self.rect.center)
        

class Enemy(Playable):
    
    def __init__(self, pos, image_data, acc=[0,0], etype=1):
        """
            Classe que representa todos os inimigos (naves).

            etype: representa o tipo ( nivel) de cada inimigo.
        """
        Playable.__init__(self, pos, image_data, acc)
        self.etype = etype
        
    def shot(self):
        pass

    def update(self, player):
        if self.etype in (2,3):
            self.move_to(player.get_pos())
        super(Enemy, self).update()


